package com.ctshk.sapp.order.train.aspecjet;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.ctshk.common.constant.RedisConstants;
import com.ctshk.common.dto.Result;
import com.ctshk.common.enums.SystemError;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.model.PageReq;
import com.ctshk.common.model.TokenUser;
import com.ctshk.common.utils.RSAUtil;
import com.ctshk.rpc.order.train.req.TrainOrderPageReq;
import com.ctshk.rpc.system.service.ISysPermissionService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.logging.log4j.util.Strings;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Objects;

/**
 * @description 权限切面处理类
 * @author 李新科
 * @date 2020/12/11
 */
@Slf4j
@Aspect
@Component
public class AuthorityAspect {

    @DubboReference
    ISysPermissionService sysPermissionService;


    /**
     * 设置权限切入点   在注解的位置切入代码
     */
    @Pointcut("@annotation(com.ctshk.common.annotations.Authority)")
    public void authorityPointCut() {
    }

    /**
     * 设置操作异常切入点记录异常日志 扫描所有controller包下操作
     */
    @Pointcut("execution(* com.ctshk..*.controller..*.*(..))")
    public void authorityExceptionPointCut() {
    }

    /**
     * 在切点之前织入
     * @param joinPoint
     * @throws Throwable
     */
    @Before("authorityPointCut()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        // 打印请求相关参数
        log.info("========================================== AUTHORITY AOP Start ==========================================");

        // 获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest) requestAttributes
                .resolveReference(RequestAttributes.REFERENCE_REQUEST);
        //获取入参
        Object[] args = joinPoint.getArgs();
        if(Objects.nonNull(args) && args.length == 1) {
            Object object = args[0];
            if(object instanceof PageReq) {
                PageReq pageReq = (PageReq) object;
                Long menuId = pageReq.getMenuId();
                Long userId = getCurrentUserId(request);
                if(menuId == null) {
                    throw new BusinessException(SystemError.SYSTEM_2106);
                }
                Result<List<Long>> permission = sysPermissionService.queryPermission(menuId, userId);

                if (!permission.isSuccess()) {
                    throw new BusinessException(SystemError.USER_1001);
                }
                List<Long> userList = permission.getData();
                if (CollectionUtils.isEmpty(userList)) {
                    throw new BusinessException(SystemError.USER_1001);
                }
                pageReq.setDataPermissionUserIds(userList);
            }

        }
    }

    /**
     * 在切点之前织入
     * @param joinPoint
     * @throws Throwable
     */
    @After("authorityPointCut()")
    public void doAfter(JoinPoint joinPoint) throws Throwable {
        log.info("========================================== AUTHORITY AOP Start ==========================================");
    }

    /**
     * 获取当前用户
     * @param request
     * @return
     */
    public TokenUser getCurrentUser(HttpServletRequest request) {
        String token = request.getHeader(RedisConstants.JWT_TOKEN_HEADER);
        if (StringUtils.isBlank(token)) {
            throw new BusinessException(SystemError.USER_1000);
        }
        TokenUser tokenUser = new TokenUser();
        try {
            token = token.replace(RedisConstants.JWT_TOKEN_PREFIX, Strings.EMPTY);
            String tokenDecrypt = RSAUtil.decryptStr(token);
            tokenUser = JSONObject.parseObject(tokenDecrypt, TokenUser.class);
        } catch (Exception e) {
            throw new BusinessException(SystemError.USER_1015);
        }

        return tokenUser;
    }

    /**
     * 获取当前用户ID
     * @param request
     * @return
     */
    public Long getCurrentUserId(HttpServletRequest request) {
        TokenUser tokenUser = getCurrentUser(request);
        return tokenUser.getId();
    }
}